local get_node = minetest.get_node

local library = defense_mob_api.library

defense_mob_api.gravity = -15

local default_prototype = {
	-- minetest properties & defaults
	initial_properties =
	{
		physical = true,
		collide_with_objects = true,
		makes_footstep_sound = true,
		visual = "mesh",
		automatic_face_movement_dir = true,
		stepheight = 0.6,
		
	},
	
	
	-- custom properties
	smart_path = true, -- Use the pathfinder
	--organize in a swarm
	swarm = false,
	
	--for switching pathfinding on and off depending on line of line_of_sight
	--if negative (default) it's always on, if >= 0 it'll switch
	mass = 1,
	gravity = defense_mob_api.gravity,
	movement = "ground", -- "ground"/"air"
	targeting = "nearest", --nearest/weak
	move_speed = 1,
	jump_height = 1,
	armor = 0,
	attack_range = 1,
	attack_damage = 1,
	attack_interval = 1,
	current_animation = nil,
	current_animation_end = 0,
	destination = nil, -- position
	last_attack_time = 0,
	timer = 0,
	media_prefix = "modname_mobname_", --set properly in register_mob
	view_range = 20,
	
	
	--default callbacks and behaviours
	damage = library.damage,
	die = library.die,
	get_staticdata = library.get_staticdata,
	is_standing = library.is_standing,
	on_death = library.on_death,
	on_punch = library.on_punch,
	on_step = library.on_step,
	remove = library.remove,
	on_activate = library.on_activate,
	
	flee = library.flee,
	hunt = library.hunt,
	jump = library.jump,
	look = library.look,
	move = library.move,
	try_attack = library.try_attack,
	
	
}






local function get_composition(f, g)
	return function(...)
		f(...)
		g(...)
	end
end

local function callable(val)
	return type(val) == "function" or
		(type(val) == "table" and
		(getmetatable(val) or {}).__call)
end

local function setup_composition_if_needed(def, prototype, field)
	local defaultval = default_prototype[field]
	local definitionval = def[field]
	
	
	if defaultval and definitionval
	then
		prototype[field] = get_composition(defaultval, definitionval)
	else
		prototype[field] = defaultval or definitionval
	end
end

function defense_mob_api.register_mob(name, def)
	local prototype = {}
	--copy default prototype
	for k, v in pairs(default_prototype)
	do
		prototype[k] = v
	end
	--overwrite fields of default prototype that def uses
	for k, v in pairs(def)
	do
		local currentv = default_prototype[k]
		if (v == nil or callable(v)) and
			(currentv == nil or callable(currentv))
		then
			setup_composition_if_needed(def, prototype, k)
		else
			prototype[k] = v
		end
	end
	prototype.media_prefix = (string.gsub(name, ":", "_") .. "_")
	
	
	
	prototype.move = defense_mob_api.library.move_methods[prototype.movement]
	prototype.find_target = defense_mob_api.library.target_methods[prototype.targeting]
	
	-- Register for pathfinding
	if defense_mob_api.pathfinder and prototype.smart_path
	then
		defense_mob_api.pathfinder:register_class(name, {
			collisionbox = prototype.collisionbox,
			jump_height = math.floor(prototype.jump_height),
			path_check = def.pathfinder_check or defense_mob_api.pathfinder.default_path_check[prototype.movement],
			cost_method = def.pathfinder_cost or defense_mob_api.pathfinder.default_cost_method[prototype.movement],
		})
	end
	
	--Register for swarming
	if prototype.swarm
	then
		prototype.swarm = defense_mob_api.Swarm()
	end
	
	minetest.register_entity(name, prototype)
end
